/**
 * Copyright (c) 2016-2020 https://github.com/zhaohuatai
 *
 * contact z_huatai@qq.com
 *  
 */

package org.zfes.snowy.core.idcenter;


/**
 * from https://github.com/twitter/snowflake/blob/master/src/main/scala/com/twitter/service/snowflake/IdWorker.scala
 *
 * @author zhaohuatai
 * @since 1.0
 */
public class SnowflakeIDWorkerB {

    private final long workerId;
    private final long datacenterId;
    
    private long idepoch=1288834974657L;//时间计算起始点，不必从1970年算起，41位支持69.7年,,Twitter 2010年开始
    
    
    public static final long defaultIdepoch = 1288834974657L;
    public static final long defaultSequence = 0L;
    
    private static final long workerIdBits = 5L;//机器标识位数
    private static final long datacenterIdBits = 5L;//数据中心标识位数
    public static final long maxWorkerId = -1L ^ (-1L << workerIdBits);//31 机器ID最大值 
    public static final long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);//31 数据中心ID最大值

    private static final long sequenceBits = 12L;//毫秒内自增位   从 1到4096，，
    private static final long workerIdShift = sequenceBits;//12 机器ID偏左移12位
    private static final long datacenterIdShift = sequenceBits + workerIdBits;//17 数据中心ID左移17位
    private static final long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;//22 时间毫秒左移22位
    private static final long sequenceMask = -1L ^ (-1L << sequenceBits);//4096

    private long lastTimestamp = -1L;
    private long sequence=0L; //起始 值。 从 1到4096，，

//    private IdWorker() {
//        this(defaultIdepoch);
//    }
//
//    private IdWorker(final long workerId) {
//   	 this(workerId, r.nextInt((int) maxDatacenterId), defaultSequence, defaultIdepoch);
//   }
    
    private SnowflakeIDWorkerB(final long datacenterId, final long workerId) {
    	 this(datacenterId, workerId, defaultSequence, defaultIdepoch);
    }
    
    //---------------
  private volatile static SnowflakeIDWorkerB singleton;  
  public static SnowflakeIDWorkerB getIdWorker(final long datacenterId, final long workerId) {  
    	  if (singleton == null) {  
    		  synchronized (SnowflakeIDWorkerB.class) {  
    			  if (singleton == null) {  
    				    singleton = new SnowflakeIDWorkerB(datacenterId,workerId); 
    			  }
    		  }
    	  }
    	return singleton;  
    }
  
// 0---0000000000 0000000000 0000000000 0000000000 0 --- 00000 --- 00000 --- 000000000000
// =   ================41位时间========================    ==10 bit 机器====     ==12bit序列号==
//默认情况下41bit的时间戳可以支持该算法使用到2082年,10bit的工作机器id可以支持1023台机器, 序列号支持1毫秒产生4095个自增序列id
// 这个工作机器id的bit段也可以进一步拆分，比如用前5个bit标记进程id，后5个bit标记线程id之类
//  ---------------------------------------------------------------------------------------------------
    //第一位为未使用（实际上也可作为long的符号位），
    //接下来的41位为毫秒级时间，
    //然后5位datacenter标识位，
    //5位机器ID（并不算标识符，实际是为线程标识），
    //然后12位该毫秒内的当前毫秒内的计数，
    //加起来刚好64位，为一个Long型。
    private SnowflakeIDWorkerB(long datacenterId,long workerId,  long sequence, long idepoch) {
    	Thread.currentThread().getId();
    	
        this.workerId = workerId;
        this.datacenterId = datacenterId;
        this.sequence = sequence;
        this.idepoch = idepoch;
        if (workerId < 0 || workerId > maxWorkerId) {
            throw new IllegalArgumentException("workerId is illegal: " + workerId);
        }
        if (datacenterId < 0 || datacenterId > maxDatacenterId) {
            throw new IllegalArgumentException("datacenterId is illegal: " + workerId);
        }
        if (idepoch >= System.currentTimeMillis()) {
            throw new IllegalArgumentException("idepoch is illegal: " + idepoch);
        }
    }

    public long getId() {
        long id = nextId();
        return id;
    }

    private synchronized long nextId() {
        long timestamp = timeGen();
        //时间错误
        if (timestamp < lastTimestamp) {
            throw new IllegalStateException("Clock moved backwards.");
        }
      //当前毫秒内 +1
        if (lastTimestamp == timestamp) {
            sequence = (sequence + 1) & sequenceMask;//& 4096,满后正好为0 ，等待下一秒
          //当前毫秒内计数满了，则等待下一秒
            if (sequence == 0) {
                timestamp = tilNextMillis(lastTimestamp);
            }
        } else {
            sequence = 0;
        }
        lastTimestamp = timestamp;
        long id = ((timestamp - idepoch) << timestampLeftShift)//
                | (datacenterId << datacenterIdShift)//
                | (workerId << workerIdShift)//
                | sequence;
        return id;
    }
  //等待下一个毫秒的到来 
    private long tilNextMillis(long lastTimestamp) {
        long timestamp = timeGen();
        while (timestamp <= lastTimestamp) {
            timestamp = timeGen();
        }
        return timestamp;
    }

    private long timeGen() {
        return System.currentTimeMillis();
    }
    public long getDatacenterId() {
        return datacenterId;
    }

    public long getWorkerId() {
        return workerId;
    }

    public long getTime() {
        return System.currentTimeMillis();
    }
    @Override
    public String toString() {
        final StringBuilder sb = new StringBuilder("IdWorker{");
        sb.append("workerId=").append(workerId);
        sb.append(", datacenterId=").append(datacenterId);
        sb.append(", idepoch=").append(idepoch);
        sb.append(", lastTimestamp=").append(lastTimestamp);
        sb.append(", sequence=").append(sequence);
        sb.append('}');
        return sb.toString();
    }
}
